package top.lixunda.ecommerce.server.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import top.lixunda.common.utils.ObjectValidators;
import top.lixunda.ecommerce.server.business.BaseServiceImpl;
import top.lixunda.ecommerce.server.business.api.entity.BusinessConstants;
import top.lixunda.ecommerce.server.business.api.entity.cache.CacheLoginUser;
import top.lixunda.ecommerce.server.user.api.entity.db.AccountDO;
import top.lixunda.ecommerce.server.user.api.entity.db.PermissionAllotDO;
import top.lixunda.ecommerce.server.user.api.entity.db.PermissionDO;
import top.lixunda.ecommerce.server.user.api.entity.db.RoleDO;
import top.lixunda.ecommerce.server.user.api.entity.dto.PermissionAllotDTO;
import top.lixunda.ecommerce.server.user.mapper.AccountMapper;
import top.lixunda.ecommerce.server.user.mapper.PermissionAllotMapper;
import top.lixunda.ecommerce.server.user.mapper.PermissionMapper;
import top.lixunda.ecommerce.server.user.mapper.RoleMapper;
import top.lixunda.ecommerce.server.user.service.IPermissionAllotService;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 权限分配表，将存在的权限分配给用户，角色或者菜单 服务实现类
 * </p>
 *
 * @author Lixunda
 * @since 2020-04-24
 */
@Slf4j
@Service
public class PermissionAllotServiceImpl
        extends BaseServiceImpl<PermissionAllotMapper, PermissionAllotDO>
        implements IPermissionAllotService {

    private final RoleMapper roleMapper;

    private final AccountMapper accountMapper;

    private final PermissionMapper permissionMapper;

    @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
    @Autowired
    public PermissionAllotServiceImpl(RoleMapper roleMapper,
                                      AccountMapper accountMapper,
                                      PermissionMapper permissionMapper) {
        this.roleMapper = roleMapper;
        this.accountMapper = accountMapper;
        this.permissionMapper = permissionMapper;
    }

    /**
     * 分配权限，只能给角色和用户分配权限
     *
     * @param list 权限操作DTO
     * @return 是否保存成功
     */
    @Override
    public Boolean allotPermission(List<PermissionAllotDTO> list) {
        // 添加用户权限
        if (ObjectValidators.isEmpty(list)) {
            throw getAppException("分配用户权限失败！参数不能为空！");
        }
        list.forEach(item -> {
            // 检验分配对象
            switch (item.getAllotPart()) {
                case BusinessConstants
                        .PERMISSION_ALLOT_PART_USER:
                    AccountDO account = accountMapper.selectById(item.getPartId());
                    if (ObjectValidators.isEmpty(account)) {
                        throw getAppException("分配用户权限失败！用户不存在：" + item.getPartId());
                    }
                    break;
                case BusinessConstants
                        .PERMISSION_ALLOT_PART_ROLE:
                    RoleDO roleDO = roleMapper.selectById(item.getPartId());
                    if (ObjectValidators.isEmpty(roleDO)) {
                        throw getAppException("分配用户权限失败！角色不存在：" + item.getPartId());
                    }
                    break;
                default:
                    log.debug("不支持的分配对象类型：" + item.getAllotPart());
                    throw getAppException("不支持的分配对象类型：" + item.getAllotPart());
            }
            // 检验权限存在性
            if (ObjectValidators.isEmpty(item.getPermissionIds())) {
                throw getAppException("分配用户权限失败！权限列表不能为空！");
            }
            int count = permissionMapper.selectCount(new LambdaQueryWrapper<PermissionDO>()
                    .in(PermissionDO::getPermissionId, item.getPermissionIds())
                    .eq(PermissionDO::getUsable, BusinessConstants.USEABLE_TRUE));
            if (count != item.getPermissionIds().size()) {
                throw getAppException("分配用户权限失败！部分权限不存在！");
            }
        });
        // 创建插入对象
        CacheLoginUser cacheLoginUser = currentLoginUserCacheNotNull();
        LocalDateTime localDateTime = LocalDateTime.now();
        List<PermissionAllotDO> insert = list.stream()
                .filter(Objects::nonNull)
                .flatMap(item -> item.getPermissionIds().stream()
                        .filter(Objects::nonNull)
                        .map(item2 -> new PermissionAllotDO()
                                .setPartId(item.getPartId())
                                .setAllotPart(item.getAllotPart())
                                .setPermissionId(item2)
                                .setAllotMode(BusinessConstants.ALLOT_MODE_HAND)
                                .setCreateTime(localDateTime)
                                .setCreateUserId(cacheLoginUser.getAccount())
                                .setCreateUserName(cacheLoginUser.getName())
                                .setCreateUserType(cacheLoginUser.getType())))
                .collect(Collectors.toList());
        if (ObjectValidators.isEmpty(insert)) {
            log.info("分配用户权限失败！插入数据为空！");
            throw getAppException("分配用户权限失败！插入数据为空！");
        }
        boolean success = this.saveBatch(insert);
        if (!success) {
            log.info("分配用户权限失败！插入数据失败！");
            throw getAppException("分配用户权限失败！插入数据失败！");
        }
        return true;
    }

    /**
     * 移除权限
     *
     * @param list 权限操作DTO
     * @return 是否移除成功
     */
    @Override
    public Boolean removePermission(List<PermissionAllotDTO> list) {
        if (ObjectValidators.isEmpty(list)) {
            throw getAppException("移除用户权限失败！参数不能为空！");
        }
        list.forEach(item -> {
            if (!BusinessConstants.PERMISSION_ALLOT_PART_ROLE.equals(item.getAllotPart())
                    && !BusinessConstants.PERMISSION_ALLOT_PART_USER.equals(item.getAllotPart())) {
                throw getAppException("移除用户权限失败！不能移除的分配对象类型：" + item.getAllotPart());
            }
        });
        CacheLoginUser cacheLoginUser = currentLoginUserCacheNotNull();
        LocalDateTime localDateTime = LocalDateTime.now();
        list.forEach(item -> this.update(new LambdaUpdateWrapper<PermissionAllotDO>()
                .set(PermissionAllotDO::getRemoveTime, localDateTime)
                .set(PermissionAllotDO::getRemoveUserId, cacheLoginUser.getAccount())
                .set(PermissionAllotDO::getRemoveUserName, cacheLoginUser.getName())
                .set(PermissionAllotDO::getRemoveTime, cacheLoginUser.getType())
                .set(PermissionAllotDO::getUsable, BusinessConstants.USEABLE_FALSE)
                .eq(PermissionAllotDO::getPartId, item.getPartId())
                .eq(PermissionAllotDO::getAllotPart, item.getAllotPart())
                .eq(PermissionAllotDO::getAllotMode, BusinessConstants.ALLOT_MODE_HAND)
                .eq(PermissionAllotDO::getUsable, BusinessConstants.USEABLE_TRUE)
                .in(PermissionAllotDO::getPermissionId, item.getPermissionIds())));
        return true;
    }

    /**
     * 根据分配编号移除权限
     *
     * @param list 分配编号列表
     * @return 是否移除成功
     */
    @Override
    public Boolean removePermissionByIds(List<Integer> list) {
        if (ObjectValidators.isEmpty(list)) {
            throw getAppException("移除用户权限失败！参数不能为空！");
        }
        CacheLoginUser cacheLoginUser = currentLoginUserCacheNotNull();
        LocalDateTime localDateTime = LocalDateTime.now();
        this.update(new LambdaUpdateWrapper<PermissionAllotDO>()
                .set(PermissionAllotDO::getRemoveTime, localDateTime)
                .set(PermissionAllotDO::getRemoveUserId, cacheLoginUser.getAccount())
                .set(PermissionAllotDO::getRemoveUserName, cacheLoginUser.getName())
                .set(PermissionAllotDO::getRemoveTime, cacheLoginUser.getType())
                .set(PermissionAllotDO::getUsable, BusinessConstants.USEABLE_FALSE)
                .eq(PermissionAllotDO::getAllotMode, BusinessConstants.ALLOT_MODE_HAND)
                .eq(PermissionAllotDO::getUsable, BusinessConstants.USEABLE_TRUE)
                .in(PermissionAllotDO::getAllotId, list));
        return true;
    }
}
